package handler

import (
	"broker-server/internal/data/user"
	"broker-server/internal/database"
	"broker-server/internal/database/tran"
	"broker-server/internal/repo"
	"broker-server/user_session"
	"common-api/logs"
	"common-api/message"
	"common-api/serialization"
	"common-api/session"
	"context"
)

var NickNameMap = make(map[string]string, 10)

type LoginHandler struct {
	Repo repo.UserRepo
}

type HeartBeatHandler struct {
}

type RegisterHandler struct {
	Repo        repo.UserRepo
	Transaction tran.Transaction
}
type PrivateChatHandler struct {
}

func (h *LoginHandler) ProcessRequest(data any, ctx context.Context) {
	s := ctx.Value("session").(*session.Session)
	resp := &message.LoginRespData{CommonResp: message.CommonRespData{}}
	msg := data.(*message.LoginReqData)
	err, u := h.Repo.FindUser(context.Background(), msg.Username, msg.Password)
	if err == nil {
		if u != nil {
			resp.CommonResp.Code = message.SuccessCode
			resp.CommonResp.Msg = "login success"
			resp.Username = msg.Username
			user_session.New(u.UserName, s)
			NickNameMap[u.UserName] = u.NickName
		} else {
			resp.CommonResp.Code = 404
			resp.CommonResp.Msg = "username or password not found"
		}
	} else {
		resp.CommonResp.Code = message.ErrorCode
		resp.CommonResp.Msg = err.Error()
	}
	err, bytes := serialization.JsonEncode(resp)
	if err != nil {
		logs.Logger.Errorf("message encode:%v", err)
		return
	}
	s.WriteMessage(&message.HeaderMessage{
		Type: message.ResponseType,
		Code: message.LoginResponseCode,
		Body: bytes,
	})
}

func (h *HeartBeatHandler) ProcessRequest(data any, ctx context.Context) {
	msg := data.(*message.HeartBeatReqData)
	user_session.RenewUserSession(msg.Username)
}

func (r *RegisterHandler) ProcessRequest(data any, ctx context.Context) {
	s := ctx.Value("session").(*session.Session)
	resp := &message.CommonRespData{}
	msg := data.(*message.RegisterReqData)
	background := context.Background()
	dbuser := &user.User{
		UserName: msg.Username,
		NickName: msg.NickName,
		PassWord: msg.PassWord,
	}
	err := r.Transaction.Action(func(conn database.DbConn) error {
		return r.Repo.SaveUser(conn, background, dbuser)
	})
	if err != nil {
		resp.Code = -1
		resp.Msg = err.Error()
	} else {
		resp.Code = message.SuccessCode
		resp.Msg = "register success"
	}
	err, bytes := serialization.JsonEncode(resp)
	if err != nil {
		logs.Logger.Errorf("message encode:%v", err)
		return
	}
	s.WriteMessage(&message.HeaderMessage{
		Type: message.ResponseType,
		Code: message.CommonResponseCode,
		Body: bytes,
	})
}

func (r *PrivateChatHandler) ProcessRequest(data any, ctx context.Context) {
	s := ctx.Value("session").(*session.Session)
	resp := &message.PrivateChatRespData{CommonResp: message.CommonRespData{}}
	msg := data.(*message.PrivateChatReqData)
	name := user_session.GetUserNameBySession(s)
	if name == "" {
		resp.CommonResp.Code = message.ErrorCode
		resp.CommonResp.Msg = "please login first"
		err, bytes := serialization.JsonEncode(resp)
		if err != nil {
			logs.Logger.Errorf("message encode:%v", err)
			return
		}
		s.WriteMessage(&message.HeaderMessage{
			Type: message.ResponseType,
			Code: message.PrivateChatResponseCode,
			Body: bytes,
		})
		return
	}
	userSession := user_session.GetUserSessionByUserName(msg.ToUserName)
	if userSession == nil {
		resp.CommonResp.Code = message.ErrorCode
		resp.CommonResp.Msg = "user not found or user is offline"
		err, bytes := serialization.JsonEncode(resp)
		if err != nil {
			logs.Logger.Errorf("message encode:%v", err)
			return
		}
		s.WriteMessage(&message.HeaderMessage{
			Type: message.ResponseType,
			Code: message.PrivateChatResponseCode,
			Body: bytes,
		})
		return
	}
	resp.CommonResp.Code = message.SuccessCode
	resp.FromNickName = NickNameMap[msg.FromUserName]
	resp.ChatMessage = msg.ChatMessage
	err, bytes := serialization.JsonEncode(resp)
	if err != nil {
		logs.Logger.Errorf("message encode:%v", err)
		return
	}
	userSession.S.WriteMessage(&message.HeaderMessage{
		Type: message.ResponseType,
		Code: message.PrivateChatResponseCode,
		Body: bytes,
	})
}
